<?php

namespace Wonfu\Reflections;

use Doctrine\Common\Annotations\AnnotationReader;
use Ds\Collection;
use Ds\Set;
use Phramz\Doctrine\Annotation\Exception\AnnotationScannerException;
use Phramz\Doctrine\Annotation\Scanner\ClassFileInfo;
use Phramz\Doctrine\Annotation\Scanner\FileInspector;
use ReflectionMethod;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\Finder as SymfonyFinder;
use Symfony\Component\Finder\SplFileInfo;
use Symfony\Component\VarDumper\Cloner\Data;
use Wonfu\Core\Annotations\RequestTag;

class Reflections
{

    private $patterns = '*.php';
    private $path;
    private $exclude;
    /**
     * @var Finder
     */
    private $finder;

    /**
     * Adds rules that files must match.
     *
     * You can use patterns (delimited with / sign), globs or simple strings.
     *
     *     Reflections->filter('*.php')
     *     Reflections->filter('/\.php$/') // same as above
     *     Reflections->filter('test.php')
     *     Reflections->filter(['test.py', 'test.php'])
     *
     * @param string|string[] $patterns A pattern (a regexp, a glob, or a string) or an array of patterns
     *
     * @return $this
     *
     * @see FilenameFilterIterator
     */
    public function filter($patterns)
    {
        $this->patterns = $patterns;
        return $this;
    }

    /**
     * @param string $path
     */
    public function include($path)
    {
        $this->path = $path;
        return $this;
    }


    /**
     * @param $path
     * @return $this
     */
    public function exclude($path)
    {
        $this->exclude = $path;
        return $this;
    }

    /**
     * @param $annotation
     * @return MethodWrapper[]
     */
    public function getMethodsWithAnnotation($annotation, $classAnnotation = null)
    {
        $result = [];
        /** @var SplFileInfo $file */
        foreach ($this->finder as $file) {
            try {
                $fileInspector = new FileInspector($file->getPathname());
                $reader = new AnnotationReader();
                $classInspector = $fileInspector->getClassInspector($reader);
                foreach ($classInspector->getMethodAnnotations() as $method => $methodAnnotations) {
                    foreach ($methodAnnotations as $methodAnnotation) {
                        if ($methodAnnotation instanceof $annotation) {
                            $class = $classInspector->getClassName();
                            $reflectionMethod = new ReflectionMethod($class, $method);
                            $methodWrapper = new MethodWrapper($methodAnnotation, $reflectionMethod);
                            $methodWrapper->setAnnotations($reader->getMethodAnnotations($reflectionMethod));
                            if ($classAnnotation) {
                                $classReflection = new \ReflectionClass($class);
                                $theClassAnnotation = $reader->getClassAnnotation($classReflection, $classAnnotation);
                            }
                            $methodWrapper->setClassAnnotation($theClassAnnotation);
                            $result[] = $methodWrapper;
                        }
                    }
                }

            } catch (AnnotationScannerException $ex) {
                continue;
            }
        }
        return $result;

    }

    public function finder()
    {
        $finder = new SymfonyFinder();
        $finder->files()
            ->name($this->patterns)
            ->in($this->path)
            ->exclude($this->exclude);
        $this->finder = $finder;
        return $this;
    }

}